package com.server.common.logistice.sfd;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.google.gson.reflect.TypeToken;
import com.server.common.code.utils.GsonUtils;
import com.server.common.logistice.sfd.create.SFDCreateOrderRequest;
import com.server.common.logistice.sfd.create.SFDCreateOrderResponse;
import com.server.common.logistice.sfd.enums.SFDApiEnum;
import com.server.common.logistice.sfd.hold.SFDHoldOrderRequest;
import com.server.common.logistice.sfd.printLabel.SFDPrintLabelRequest;
import com.server.common.logistice.sfd.track.SFDGetTrackRequest;
import com.server.common.logistice.sfd.track.SFDGetTrackResponse;
import com.server.common.logistics.base.BaseLogisticsService;
import com.server.common.logistics.enums.LogisticsCompanyEnum;
import com.server.common.logistics.enums.ApiEnum;
import com.server.common.logistics.request.LogisticsRequest;
import com.server.common.logistics.result.CreateOrderResult;
import com.server.common.logistics.result.GetTrackResult;
import com.server.common.logistics.result.HoldOrderResult;
import com.server.common.logistics.result.PrintLabelSyncResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import sun.misc.BASE64Encoder;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.*;

@Component
@Slf4j
public class SFDServiceImpl extends BaseLogisticsService {

    @Resource
    private SFDConfig sfdConfig;

    /**
     * 计算数字签名
     * @author LXC
     * @date 2022-03-24 14:54
     */
    private static String getMsgDigest(String checkWord,String msgData,String timeStamp){
        try {
            String toVerifyText = msgData+timeStamp + checkWord;
            toVerifyText = URLEncoder.encode(toVerifyText,"UTF-8");

            //进行Md5加密
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(toVerifyText.getBytes(StandardCharsets.UTF_8));
            byte[] md = md5.digest();
            //通过BASE64生成数字签名
            return new BASE64Encoder().encode(md);
        }catch (Exception e){
            log.error("数字签名失败");
        }
        return "";
    }

    @Override
    public <T> SFDResponse<T> baseRequest(ApiEnum apiEnum, Object params){
        String timeStamp = String.valueOf(System.currentTimeMillis());

        String paramsJSONStr = GsonUtils.getGson().toJson(params);
        Map<String, Object> publicParamsMap = new HashMap<String, Object>();
        publicParamsMap.put("partnerID", sfdConfig.getClientCode());  // 顾客编码
        publicParamsMap.put("requestID", UUID.randomUUID().toString().replace("-", ""));
        publicParamsMap.put("serviceCode",apiEnum.getMethod());// 接口服务码
        publicParamsMap.put("timestamp", timeStamp);
        publicParamsMap.put("msgData", paramsJSONStr);
        publicParamsMap.put("msgDigest", getMsgDigest(sfdConfig.getCheckWord(),paramsJSONStr+"",timeStamp));

        String body = HttpUtil.post(sfdConfig.getUrl(), publicParamsMap);
        JSONObject jsonObject = JSONUtil.parseObj(body);

        SFDResponse<T> sfdResponse = new SFDResponse<>();
        sfdResponse.setApiErrorMsg(jsonObject.getStr("apiErrorMsg"));
        sfdResponse.setApiResponseID(jsonObject.getStr("apiResponseID"));
        sfdResponse.setApiResultCode(jsonObject.getStr("apiResultCode"));
        String apiResultData = jsonObject.getStr("apiResultData");

        if(!ObjectUtils.isEmpty(apiResultData)){
            sfdResponse.setApiResultData(GsonUtils.getGson().fromJson(apiResultData,new TypeToken<T>(){}.getType()));
        }

        return sfdResponse;
    }

    @Override
    public CreateOrderResult createOrder(LogisticsRequest orderRequest) {
        CreateOrderResult createOrderResult = new CreateOrderResult();

        try {
            if(!(orderRequest instanceof SFDCreateOrderRequest)){
                createOrderResult.setErrorMsg("物流下单有误");
                return createOrderResult;
            }

            SFDResponse<SFDCreateOrderResponse> sfdResponse = baseRequest(SFDApiEnum.CREATE_ORDER, orderRequest);

            if(!sfdResponse.responseOk()){
                createOrderResult.setErrorMsg(sfdResponse.getApiErrorMsg());
                return createOrderResult;
            }

            if(sfdResponse.dataEmpty()){
                createOrderResult.setErrorMsg("物流下单有误");
                return createOrderResult;
            }

            SFDResponse.ApiResultData<SFDCreateOrderResponse> apiResultData = sfdResponse.getApiResultData();

            if(!apiResultData.responseOk()){
                createOrderResult.setErrorMsg(apiResultData.getErrorMsg());
                return createOrderResult;
            }

            if(apiResultData.dataEmpty()){
                createOrderResult.setErrorMsg("下单失败");
                return createOrderResult;
            }
            SFDCreateOrderResponse msgData = apiResultData.getMsgData();

            List<SFDCreateOrderResponse.WaybillNoInfoList> waybillNoInfoList = msgData.getWaybillNoInfoList();
            if(ObjectUtils.isEmpty(waybillNoInfoList)){
                createOrderResult.setErrorMsg("下单失败");
                return createOrderResult;
            }

            SFDCreateOrderResponse.WaybillNoInfoList waybillNoInfoFirst = CollUtil.getFirst(waybillNoInfoList);

            createOrderResult.setThirdOrderId(UUID.randomUUID().toString().replace("-",""));
            createOrderResult.setTrackingNumber(waybillNoInfoFirst.getTrackingNumber());

        }catch (Exception e){
            log.error("下单失败",e);
            createOrderResult.setErrorMsg("下单失败");
        }

        return createOrderResult;
    }

    @Override
    public HoldOrderResult holdOrder(LogisticsRequest holdOrderRequest) {
        HoldOrderResult holdOrderResult = new HoldOrderResult();
        holdOrderResult.setHoldFlag(true);

        try {
            if(!(holdOrderRequest instanceof SFDHoldOrderRequest)){
                holdOrderResult.setErrorMsg("拦截订单参数有误");
                return holdOrderResult;
            }

            SFDResponse<Void> sfdResponse = baseRequest(SFDApiEnum.HOLD_ORDER, holdOrderRequest);

            if(!sfdResponse.responseOk()){
                holdOrderResult.setErrorMsg(sfdResponse.getApiErrorMsg());
                holdOrderResult.setHoldFlag(false);
            }

            if(sfdResponse.dataEmpty()){
                holdOrderResult.setErrorMsg("拦截订单失败");
                holdOrderResult.setHoldFlag(false);
            }

            SFDResponse.ApiResultData<Void> apiResultData = sfdResponse.getApiResultData();

            if(!apiResultData.responseOk()){
                holdOrderResult.setErrorMsg(apiResultData.getErrorMsg());
                holdOrderResult.setHoldFlag(false);
            }
        }catch (Exception e){
            log.error("拦截订单失败",e);
            holdOrderResult.setErrorMsg("拦截订单失败");
        }

        return holdOrderResult;
    }

    @Override
    public GetTrackResult getTracking(LogisticsRequest getTrackRequest) {
        GetTrackResult getTrackResult = new GetTrackResult();

        try {
            if(!(getTrackRequest instanceof SFDGetTrackRequest)){
                getTrackResult.setErrorMsg("获取物流轨迹参数有误");
                return getTrackResult;
            }

            SFDResponse<SFDGetTrackResponse> sfdResponse = baseRequest(SFDApiEnum.GET_TRACK, getTrackRequest);

            if(!sfdResponse.responseOk()){
                getTrackResult.setErrorMsg(sfdResponse.getApiErrorMsg());
                return getTrackResult;
            }

            if(sfdResponse.dataEmpty()){
                getTrackResult.setErrorMsg("获取物流轨迹失败");
                return getTrackResult;
            }

            SFDResponse.ApiResultData<SFDGetTrackResponse> apiResultData = sfdResponse.getApiResultData();

            if(!apiResultData.getSuccess()){
                getTrackResult.setErrorMsg(apiResultData.getErrorMsg());
                return getTrackResult;
            }

            SFDGetTrackResponse msgData = apiResultData.getMsgData();
            if(ObjectUtils.isEmpty(msgData)){
                getTrackResult.setErrorMsg("获取物流轨迹失败");
                return getTrackResult;
            }

            List<SFDGetTrackResponse.TrackData> trackDataList = msgData.getTrackDataList();
            if(ObjectUtils.isEmpty(trackDataList)){
                getTrackResult.setTackList(new ArrayList<>());
                return getTrackResult;
            }
            SFDGetTrackResponse.TrackData trackData = CollUtil.getFirst(trackDataList);

            getTrackResult.setTrackingNumber(trackData.getTrackingNumber());

            List<SFDGetTrackResponse.TrackData.TrackDetailData> trackDetailDataList = trackData.getTrackDetailDataList();
            if(ObjectUtils.isEmpty(trackDetailDataList)){
                return getTrackResult;
            }

            //起始时间
            SFDGetTrackResponse.TrackData.TrackDetailData startTrackDetailData = CollUtil.getFirst(trackDetailDataList);
            //最后一个物流时间
            SFDGetTrackResponse.TrackData.TrackDetailData overTrackDetailData = CollUtil.getLast(trackDetailDataList);
            //运输时间
            long transitDay = DateUtil.between(DateUtil.parseDate(startTrackDetailData.getAcceptTime()), DateUtil.parseDate(overTrackDetailData.getAcceptTime()), DateUnit.DAY);
            getTrackResult.setTransitDay((int) Math.max(transitDay,0));

            //停留时间
            long stayDay = DateUtil.between(DateUtil.parseDate(overTrackDetailData.getAcceptTime()), DateUtil.date(),DateUnit.DAY);
            getTrackResult.setStayDay((int) Math.max(stayDay,0));

            //
            for (SFDGetTrackResponse.TrackData.TrackDetailData trackDetailData :trackDetailDataList){
                GetTrackResult.Tack tack = new GetTrackResult.Tack();
                tack.setTime(trackDetailData.getAcceptTime());
                tack.setContent(trackDetailData.getOpcode());
                tack.setLocation(trackDetailData.getAcceptAddress());
                tack.setStatusCode(trackDetailData.getOpcode());
                tack.setStatusName(trackDetailData.getState());
                getTrackResult.getTackList().add(tack);
            }
        }catch (Exception e){
            log.error("获取物流轨迹失败",e);
            getTrackResult.setErrorMsg("获取物流轨迹失败");
        }

        return getTrackResult;
    }

    @Override
    public PrintLabelSyncResult printLabelSync(LogisticsRequest printLabelSyncRequest) {
        PrintLabelSyncResult printLabelSyncResult = new PrintLabelSyncResult();

        try {

            if(!(printLabelSyncRequest instanceof SFDPrintLabelRequest)){
                printLabelSyncResult.setErrorMsg("打印面单请求参数有误");
                return printLabelSyncResult;
            }

            SFDPrintLabelRequest sfdPrintLabelRequest = (SFDPrintLabelRequest) printLabelSyncRequest;
            SFDResponse<SFDGetTrackResponse> sfdResponse = baseRequest(SFDApiEnum.PRINT_LABEL, sfdPrintLabelRequest);

            if(!sfdResponse.responseOk()){
                printLabelSyncResult.setErrorMsg(sfdResponse.getApiErrorMsg());
                return printLabelSyncResult;
            }

            if(!sfdResponse.dataEmpty()){
                printLabelSyncResult.setErrorMsg("打印面单失败");
                return printLabelSyncResult;
            }
            SFDResponse.ApiResultData<SFDGetTrackResponse> apiResultData = sfdResponse.getApiResultData();

            if(!apiResultData.responseOk()){
                printLabelSyncResult.setErrorMsg(sfdResponse.getApiErrorMsg());
                return printLabelSyncResult;
            }

            SFDResponse.ApiResultData.PrintLabelObj printLabelObj = apiResultData.getPrintLabelObj();

            if(ObjectUtils.isEmpty(printLabelObj)){
                printLabelSyncResult.setErrorMsg("打印面单失败");
                return printLabelSyncResult;
            }

            List<SFDResponse.ApiResultData.PrintLabelObj.PrintFile> fileList = printLabelObj.getFiles();
            if(ObjectUtils.isEmpty(fileList)){
                printLabelSyncResult.setErrorMsg("打印面单失败");
                return printLabelSyncResult;
            }
            SFDResponse.ApiResultData.PrintLabelObj.PrintFile printFile = CollUtil.getFirst(fileList);

            HttpRequest httpRequest = HttpUtil.createGet(printFile.getUrl());
            httpRequest.header("X-Auth-token",printFile.getToken());
            byte[] bytes = httpRequest.execute().bodyBytes();
            printLabelSyncResult.setBytes(bytes);
        }catch (Exception e){
            log.error("打印面单失败",e);
            printLabelSyncResult.setErrorMsg("打印面单失败");
        }

        return printLabelSyncResult;
    }

    @Override
    public LogisticsCompanyEnum getLogisticsCompanyEnum() {
        return LogisticsCompanyEnum.SFD;
    }
}
